package com.tjsoft.system.util;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Restrictions;
import org.springframework.util.Assert;
import org.springside.modules.orm.Page;
import org.springside.modules.orm.PropertyFilter;
import org.springside.modules.orm.hibernate.HibernateDao;

@SuppressWarnings("unchecked")
public class MyHibernateDao<T, PK extends Serializable> extends HibernateDao<T, PK> {

	/**
	 * 按属性过滤条件列表分页查找对象.
	 */
	@Override
	public Page<T> findPage(final Page<T> page, final List<PropertyFilter> filters) {
		Criterion[] criterions = buildCriterionByPropertyFilter(filters);
		return findPage(filters,page, criterions);
	}
	
	public Page<T> findPageDistinct(final Page<T> page, final List<PropertyFilter> filters) {
		Criterion[] criterions = buildCriterionByPropertyFilter(filters);
		return findPageDistinct(filters,page, criterions);
	}
	
	/**
	 * 按Criteria分页查询.
	 * 并去掉重复值
	 * @param page 分页参数.
	 * @param criterions 数量可变的Criterion.
	 * 
	 * @return 分页查询结果.附带结果列表及所有查询输入参数.
	 */
	public Page<T> findPageDistinct(final List<PropertyFilter> filters,final Page<T> page, final Criterion... criterions) {
		Assert.notNull(page, "page不能为空");

		Criteria c = createCriteria(filters,criterions);
		c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);    //设置ENTITY级的DISTINCT模式，根实体
		if (page.isAutoCount()) {
			long totalCount = countCriteriaResult(c);
			page.setTotalCount(totalCount);
		}

		setPageParameterToCriteria(c, page);
		List result = c.list();
		page.setResult(result);
		return page;
	}
	
	/**
	 * 按Criteria分页查询.
	 * 
	 * @param page 分页参数.
	 * @param criterions 数量可变的Criterion.
	 * 
	 * @return 分页查询结果.附带结果列表及所有查询输入参数.
	 */
	public Page<T> findPage(final List<PropertyFilter> filters,final Page<T> page, final Criterion... criterions) {
		Assert.notNull(page, "page不能为空");

		Criteria c = createCriteria(filters,criterions);

		if (page.isAutoCount()) {
			long totalCount = countCriteriaResult(c);
			page.setTotalCount(totalCount);
		}

		setPageParameterToCriteria(c, page);
		List result = c.list();
		page.setResult(result);
		return page;
	}
	
	/**
	 * 根据Criterion条件创建Criteria.
	 * 与find()函数可进行更加灵活的操作.
	 * 
	 * @param criterions 数量可变的Criterion.
	 */
	public Criteria createCriteria(final List<PropertyFilter> filters,final Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(entityClass);
		Set<String> paras = new HashSet<String>();
		for(PropertyFilter pf : filters){
			String pn = pf.getPropertyName();
			String[] pns = pn.split("-");
			/**修改为支持多级导航查询 hj*/
			
			String name = "";
			String nameAs = "";
			for(int i=0;i<pns.length-1;i++){
				name += pns[i]+".";
				nameAs = pns[i];
				String tmp = name.substring(0,name.length()-1);
				if(pns.length>1 && !paras.contains(tmp)){
					paras.add(tmp);
					criteria.createAlias(tmp, nameAs);
				}
			}
		}
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		return criteria;
	}
	
	/**
	 * 按属性条件列表创建Criterion数组,辅助函数.
	 */
	@Override
	protected Criterion[] buildCriterionByPropertyFilter(final List<PropertyFilter> filters) {
		List<Criterion> criterionList = new ArrayList<Criterion>();
		for (PropertyFilter filter : filters) {
			if (!filter.hasMultiProperties()) { //只有一个属性需要比较的情况.
				String pname = filter.getPropertyName();
				String[] pnames = pname.split("-");
				if(pnames.length>=3){
					pname = pnames[pnames.length-2] +"." + pnames[pnames.length-1];
				}else{
					pname = pname.replaceAll("-", ".");
				}
				Criterion criterion = buildCriterion(pname, filter.getMatchValue(), filter
						.getMatchType());
				criterionList.add(criterion);
			} else {//包含多个属性需要比较的情况,进行or处理.
				Disjunction disjunction = Restrictions.disjunction();
				for (String param : filter.getPropertyNames()) {
					Criterion criterion = buildCriterion(param.replaceAll("-", "."), filter.getMatchValue(), filter.getMatchType());
					disjunction.add(criterion);
				}
				criterionList.add(disjunction);
			}
		}
		return criterionList.toArray(new Criterion[criterionList.size()]);
	}

	public T load(final PK id) {
		Assert.notNull(id, "id不能为空");
		return (T) getSession().load(entityClass, id);
	}
	
	public T get(final PK id) {
		Assert.notNull(id, "id不能为空");
		return (T) getSession().get(entityClass, id);
	}
}
